home *** CD-ROM | disk | FTP | other *** search
Modula Implementation | 1986-03-04 | 21.9 KB | 712 lines |
- IMPLEMENTATION MODULE SyntaxAnalyzer;
- (* Analyzes the operands to provide information for CodeGenerator *)
-
- FROM Strings IMPORT
- Length;
-
- FROM LongNumbers IMPORT
- LONG, LongAdd, LongSub, CardToLong, StringToLong, BinStrToLong;
-
- FROM SymbolTable IMPORT
- SortSymTab, ReadSymTab;
-
- FROM ErrorX68 IMPORT
- ErrorType, Error;
-
- FROM Parser IMPORT
- OPERAND, SrcLoc;
-
- FROM CodeGenerator IMPORT
- LZero, AddrCnt, Pass2; (* BOOLEAN Switch *)
-
-
- CONST
- Zero = 30H; (* The Ordinal value of the Character '0' *)
- Seven = 37H; (* The Ordinal value of the Character '7' *)
- Quote = 47C;
-
- (*---
- TYPE
- OpMode = (DReg, (* Data Register *)
- ARDir, (* Address Register Direct *)
- ARInd, (* Address Register Indirect *)
- ARPost, (* Address Register with Post-Increment *)
- ARPre, (* Address Register with Pre-Decrement *)
- ARDisp, (* Address Register with Displacement *)
- ARDisX, (* Address Register with Disp. & Index *)
- AbsW, (* Absolute Word (16-bit Address) *)
- AbsL, (* Absolute Word (32-bit Address) *)
- PCDisp, (* Program Counter Relative, with Displacement *)
- PCDisX, (* Program Counter Relative, with Disp. & Index *)
- Imm, (* Immediate *)
- MultiM, (* Multiple Register Move *)
- SR, (* Status Register *)
- CCR, (* Condition Code Register *)
- USP, (* User's Stack Pointer *)
- Null); (* Error Condition, or Operand missing *)
-
- Xtype = (X0, Dreg, Areg);
- SizeType = (S0, Byte, Word, S3, Long);
-
- OpConfig = RECORD (* OPERAND CONFIGURATION *)
- Mode : OpMode;
- Value : LONG;
- Loc : CARDINAL; (* Location of Operand on line *)
- Rn : CARDINAL; (* Register number *)
- Xn : CARDINAL; (* Index Reg. nbr. *)
- Xsize : SizeType; (* size of Index *)
- X : Xtype; (* Is index Data or Address reg? *)
- END;
- ---*)
-
- VAR
- AbsSize : SizeType; (* size of operand (Absolute only) *)
-
-
- PROCEDURE StrToCard (s : ARRAY OF CHAR; VAR C : CARDINAL) : BOOLEAN;
- (* Adapted form Hochstrasser Modula-2 System for Z80 CP/M *)
-
- CONST
- maxCard = 65535;
- maxNum = 6553; (* cannot add another digit if C >= maxNum *)
-
- VAR
- i, top : CARDINAL;
- digit : INTEGER;
- gotOne : BOOLEAN;
-
- BEGIN
- i := 0;
- C := 0;
- top := HIGH (s);
- gotOne := FALSE;
-
- LOOP
- digit := ORD (s[i]) - Zero;
- IF (digit >= 0) AND (digit <= 9) AND (i <= top) AND
- ((C <= maxNum) OR (maxCard DIV C >= 10) AND
- (maxCard - C * 10 >= CARDINAL (digit)))
- THEN
- gotOne := TRUE;
- C := C * 10 + CARDINAL (digit);
- INC (i);
- ELSE
- EXIT;
- END;
- END;
-
- RETURN ((s[i] = 0C) OR (i > top)) AND gotOne;
- END StrToCard;
-
-
-
- PROCEDURE CalcValue (Operand : OPERAND; VAR Value : LONG);
- (* Calculates left and right values for GetValue *)
-
- VAR
- Neg : BOOLEAN;
- Dup : BOOLEAN;
- Num : CARDINAL;
- NumSyms : CARDINAL;
-
- BEGIN
- IF Operand[0] = '-' THEN
- Neg := TRUE;
- Operand[0] := '0';
- ELSE
- Neg := FALSE;
- END;
-
- IF StrToCard (Operand, Num) THEN
- (* It is a number *)
- CardToLong (Num, Value);
- IF Neg THEN
- LongSub (LZero, Value, Value);
- END;
- ELSIF StringToLong (Operand, Value) THEN
- (* It is a HEX number *)
- ELSIF BinStrToLong (Operand, Value) THEN
- (* It is a Binary number *)
- ELSIF (Operand[0] = Quote) AND (Operand[2] = Quote) THEN
- CardToLong (ORD (Operand[1]), Value);
- ELSIF (Length (Operand) = 1) AND (Operand[0] = '*') THEN
- Value := AddrCnt;
- ELSE
- (* It is a label, but may be undefined! *)
- IF NOT Pass2 THEN
- SortSymTab (NumSyms);
- END;
- IF NOT ReadSymTab (Operand, Value, Dup) THEN
- Error (SrcLoc, Undef);
- END;
- IF Dup THEN
- Error (SrcLoc, SymDup);
- END;
- END;
- END CalcValue;
-
-
-
- PROCEDURE GetValue (Operand : OPERAND; VAR Value : LONG);
- (* determines value of operand (in Decimal, HEX, or via Symbol Table) *)
-
- VAR
- TempOp : OPERAND;
- TempVal : LONG;
- c, op : CHAR;
- i, j : CARDINAL;
- InQuotes : BOOLEAN;
-
- BEGIN
- i := 0;
- Value := LZero;
- InQuotes := FALSE;
- op := '+';
- REPEAT
- j := 0;
- LOOP
- c := Operand[i];
- TempOp[j] := c;
- IF c = Quote THEN
- InQuotes := NOT InQuotes;
- END;
- INC (i); INC (j);
- IF c = 0C THEN
- EXIT;
- END;
- IF (c = '+') AND (NOT InQuotes) THEN
- EXIT;
- END;
- IF (c = '-') AND (i > 1) AND (NOT InQuotes) THEN
- EXIT;
- END;
- END;
- TempOp[j - 1] := 0C; (* in case c is +/- *)
- CalcValue (TempOp, TempVal);
- IF op = '-' THEN
- LongSub (Value, TempVal, Value);
- ELSE
- LongAdd (Value, TempVal, Value);
- END;
- op := c;
- UNTIL op = 0C;
- END GetValue;
-
-
-
- PROCEDURE GetSize (VAR Symbol : ARRAY OF CHAR; VAR Size : SizeType);
- (* determines size of opcode/operand: Byte, Word, Long *)
-
- VAR
- i : CARDINAL;
- c : CHAR;
-
- BEGIN
- i := 0;
- REPEAT
- c := Symbol[i];
- INC (i);
- UNTIL (c = 0C) OR (c = '.');
-
- IF c = 0C THEN
- Size := Word; (* Default to size Word = 16 bits *)
- ELSE
- c := Symbol[i]; (* Record size extension *)
- Symbol[i - 1] := 0C; (* Chop size extension off *)
- IF (c = 'B') OR (c = 'S') THEN (* Byte or Short Branch/Jump *)
- Size := Byte;
- ELSIF c = 'L' THEN
- Size := Long;
- ELSE
- Size := Word; (* Default size *)
- END;
- END;
- END GetSize;
-
-
-
- PROCEDURE GetAbsSize (VAR Symbol : ARRAY OF CHAR; VAR AbsSize : SizeType);
- (* determines size of operand: Word or Long *)
-
- VAR
- i : CARDINAL;
- c : CHAR;
- ParCnt : INTEGER;
-
- BEGIN
- ParCnt := 0;
- i := 0;
- REPEAT
- c := Symbol[i];
- IF c = '(' THEN
- INC (ParCnt);
- END;
- IF c = ')' THEN
- DEC (ParCnt);
- END;
- INC (i);
- UNTIL (c = 0C) OR ((c = '.') AND (ParCnt = 0));
-
- IF c = 0C THEN
- AbsSize := Long;
- ELSE
- c := Symbol[i]; (* Record size extension *)
- Symbol[i - 1] := 0C; (* Chop size extension off *)
- IF (c = 'W') OR (c = 'S') THEN
- AbsSize := Word;
- ELSE
- AbsSize := Long;
- END;
- END;
- END GetAbsSize;
-
-
-
- PROCEDURE GetInstModeSize (Mode : OpMode; Size : SizeType;
- VAR InstSize : CARDINAL) : CARDINAL;
- (* Determines the size for the various instruction modes. *)
-
- VAR
- n : CARDINAL;
-
- BEGIN
- CASE Mode OF
- ARDisp,
- ARDisX,
- PCDisp,
- PCDisX,
- AbsW : n := 2;
- | AbsL : n := 4;
- | MultiM : IF Pass2 THEN
- n := 0; (* accounted for by code generator *)
- ELSE
- n := 2;
- END;
- | Imm : IF Size = Long THEN
- n := 4;
- ELSE
- n := 2;
- END;
- ELSE
- n := 0;
- END;
-
- INC (InstSize, n);
- RETURN (n * 2);
- END GetInstModeSize;
-
-
-
- PROCEDURE GetOperand (Oper : OPERAND; VAR Op : OpConfig);
- (* Finds mode and value for source or destination operand *)
-
- VAR
- ch : CHAR;
- C : CARDINAL; (* holds the ordinal value of a charcter *)
- i, j : CARDINAL;
- Len : CARDINAL; (* Calculated Length of Oper *)
- TempOp : OPERAND;
- MultFlag : BOOLEAN;
-
- BEGIN
- Op.Mode := Null; Op.X := X0;
- Len := Length (Oper);
-
- IF Len = 0 THEN
- RETURN;
- END;
-
- GetAbsSize (Oper, AbsSize);
-
- IF Oper[0] = '#' THEN (* Immediate *)
- IF Pass2 THEN
- i := 0;
- REPEAT
- INC (i);
- Oper[i - 1] := Oper[i];
- UNTIL Oper[i] = 0C;
- GetValue (Oper, Op.Value);
- END;
- Op.Mode := Imm;
- RETURN;
- END;
-
- IF Len = 2 THEN (* possible Addr or Data Register *)
- C := ORD (Oper[1]);
- IF (Oper[0] = 'S') AND (Oper[1] = 'R') THEN
- (* Status Register *)
- Op.Mode := SR;
- RETURN;
- ELSIF (Oper[0] = 'S') AND (Oper[1] = 'P') THEN
- (* Stack Pointer *)
- Op.Mode := ARDir;
- Op.Rn := 7;
- RETURN;
- ELSIF (C >= Zero) AND (C <= Seven) THEN
- (* Looks Like an Addr or Data Reg *)
- IF Oper[0] = 'A' THEN (* Address Register *)
- Op.Mode := ARDir;
- Op.Rn := C - Zero;
- RETURN;
- ELSIF Oper[0] = 'D' THEN (* Data Register *)
- Op.Mode := DReg;
- Op.Rn := C - Zero;
- RETURN;
- ELSE
- (* may be a label -- ignore for now *)
- END;
- ELSE
- (* may be a label -- ignore for now *)
- END;
- END;
-
- IF Len = 3 THEN
- IF (Oper[0] = 'C') AND (Oper[1] = 'C') AND (Oper[2] = 'R') THEN
- (* Condition Code Register *)
- Op.Mode := CCR;
- RETURN;
- ELSIF (Oper[0] = 'U') AND (Oper[1] = 'S') AND (Oper[2] = 'P') THEN
- (* User's Stack Pointer *)
- Op.Mode := USP;
- RETURN;
- ELSE
- (* may be a label -- ignore for now *)
- END;
- END;
-
- IF (Len = 4) AND (Oper[0] = '(') AND (Oper[3] = ')') THEN
- IF (Oper[1] = 'S') AND (Oper[2] = 'P') THEN
- Op.Mode := ARInd;
- Op.Rn := 7;
- RETURN;
- ELSIF Oper[1] = 'A' THEN
- C := ORD (Oper[2]);
- IF (C >= Zero) AND (C <= Seven) THEN
- Op.Mode := ARInd;
- Op.Rn := C - Zero;
- RETURN;
- ELSE
- Error (Op.Loc, SizeErr);
- RETURN;
- END;
- ELSE
- Error (Op.Loc, AddrErr);
- RETURN;
- END;
- END;
-
- IF (Len = 5) AND (Oper[0] = '(')
- AND (Oper[3] = ')') AND (Oper[4] = '+') THEN
- (* Address Indirect with Post Inc *)
- IF (Oper[1] = 'S') AND (Oper[2] = 'P') THEN
- (* System Stack Pointer *)
- Op.Mode := ARPost;
- Op.Rn := 7;
- RETURN
- ELSIF Oper[1] = 'A' THEN
- C := ORD (Oper[2]);
- IF (C >= Zero) AND (C <= Seven) THEN
- Op.Mode := ARPost;
- Op.Rn := C - Zero;
- RETURN;
- ELSE
- Error (Op.Loc, SizeErr);
- RETURN;
- END;
- ELSE
- Error (Op.Loc, AddrErr);
- RETURN;
- END;
- END;
-
- IF (Len = 5) AND (Oper[0] = '-')
- AND (Oper[1] = '(') AND (Oper[4] = ')') THEN
- IF (Oper[2] = 'S') AND (Oper[3] = 'P') THEN
- (* System Stack Pointer *)
- Op.Mode := ARPre;
- Op.Rn := 7;
- RETURN;
- ELSIF Oper[2] = 'A' THEN
- C := ORD (Oper[3]);
- IF (C >= Zero) AND (C <= Seven) THEN
- Op.Mode := ARPre;
- Op.Rn := C - Zero;
- RETURN;
- ELSE
- Error (Op.Loc, SizeErr);
- RETURN;
- END;
- ELSE
- Error (Op.Loc, AddrErr);
- RETURN;
- END;
- END;
-
- (* Try to split off displacement (if present) *)
- i := 0;
- ch := Oper[i];
- WHILE (ch # '(') AND (ch # 0C) DO (* move to TempOp *)
- TempOp[i] := ch;
- INC (i);
- ch := Oper[i];
- END;
- TempOp[i] := 0C; (* Displacement (it it exists) now in TempOp *)
-
- IF (ch = '(') AND (TempOp[i - 1] # '+') THEN
- (* looks like a displacement mode *)
- IF Pass2 THEN
- GetValue (TempOp, Op.Value); (* Value of Disp. *)
- END;
- j := 0;
- REPEAT (* put rest of operand (eg. (An,Xi) in TempOp *)
- ch := Oper[i];
- TempOp[j] := ch;
- INC (i); INC (j);
- UNTIL ch = 0C;
- IF Length (TempOp) > 4 THEN (* Index may be present *)
- i := 4; (* Index starts at 4 *)
- j := 0;
- REPEAT (* put Xi in Oper *)
- ch := TempOp[i];
- Oper[j] := ch;
- INC (i); INC (j);
- UNTIL ch = 0C;
-
- IF Oper[j - 2] = ')' THEN
- Oper[j - 2] := 0C;
- ELSE
- Error (Op.Loc, AddrErr);
- RETURN;
- END;
-
- GetSize (Oper, Op.Xsize);
- IF Op.Xsize = Byte THEN
- Error (Op.Loc, SizeErr);
- RETURN;
- END;
-
- C := ORD (Oper[1]);
- IF (Oper[0] = 'S') AND (Oper[1] = 'P') THEN
- (* Stack Pointer *)
- Op.X := Areg;
- Op.Xn := 7;
- ELSIF Oper[0] = 'A' THEN
- IF (C >= Zero) AND (C <= Seven) THEN
- Op.X := Areg;
- Op.Xn := C - Zero;
- ELSE
- Error (Op.Loc, SizeErr);
- RETURN;
- END;
- ELSIF Oper[0] = 'D' THEN
- IF (C >= Zero) AND (C <= Seven) THEN
- Op.X := Dreg;
- Op.Xn := C - Zero;
- ELSE
- Error (Op.Loc, SizeErr);
- RETURN;
- END;
- ELSE
- Error (Op.Loc, AddrErr);
- RETURN;
- END;
-
- IF (TempOp[1] = 'P') AND (TempOp[2] = 'C') THEN
- Op.Mode :=PCDisX;
- RETURN;
- ELSIF (TempOp[1] = 'S') AND (TempOp[2] = 'P') THEN
- (* Stack Pointer *)
- Op.Rn := 7;
- Op.Mode := ARDisX;
- RETURN;
- ELSIF TempOp[1] = 'A' THEN
- C := ORD (TempOp[2]);
- IF (C >= Zero) AND (C <= Seven) THEN
- Op.Rn := C - Zero;
- Op.Mode := ARDisX;
- RETURN;
- ELSE
- Error (Op.Loc, SizeErr);
- RETURN;
- END;
- ELSE
- Error (Op.Loc, AddrErr);
- RETURN;
- END;
- ELSE (* No Index *)
- IF (TempOp[1] = 'P') AND (TempOp[2] = 'C') THEN
- Op.Mode := PCDisp;
- RETURN;
- ELSIF (TempOp[1] = 'S') AND (TempOp[2] = 'P') THEN
- (* Stack Pointer *)
- Op.Mode := ARDisp;
- Op.Rn := 7;
- RETURN;
- ELSIF TempOp[1] = 'A' THEN
- C := ORD (TempOp[2]);
- IF (C >= Zero) AND (C <= Seven) THEN
- Op.Rn := C - Zero;
- Op.Mode := ARDisp;
- RETURN;
- ELSE
- Error (Op.Loc, SizeErr);
- RETURN;
- END;
- ELSE
- Error (Op.Loc, AddrErr);
- RETURN;
- END;
- END;
- END;
-
- (* Check to see if this could be a register list for MOVEM: *)
- i := 0;
- MultFlag := FALSE;
- LOOP
- ch := Oper[i]; INC (i);
- IF ch = 0C THEN
- MultFlag := FALSE;
- EXIT;
- END;
- IF (ch = 'A') OR (ch = 'D') THEN
- ch := Oper[i]; INC (i); C := ORD (ch);
- IF ch = 0C THEN
- MultFlag := FALSE;
- EXIT;
- END;
- IF (C >= Zero) AND (C <= Seven) THEN
- ch := Oper[i]; INC (i);
- IF ch = 0C THEN
- EXIT
- END;
- IF (ch = '/') OR (ch = '-') THEN
- MultFlag := TRUE;
- END;
- ELSE
- MultFlag := FALSE;
- EXIT;
- END;
- ELSE
- MultFlag := FALSE;
- EXIT;
- END;
- END;
- IF MultFlag THEN
- Op.Mode := MultiM;
- RETURN;
- END;
-
- (* Must be absolute mode! *)
- IF Pass2 THEN
- GetValue (Oper, Op.Value);
- END;
- IF AbsSize = Word THEN
- Op.Mode := AbsW;
- ELSE
- Op.Mode := AbsL;
- END;
- END GetOperand;
-
-
-
- PROCEDURE GetMultReg (Oper : OPERAND; PreDec : BOOLEAN;
- Loc : CARDINAL; VAR MultExt : BITSET);
- (* Builds a BITSET marking each register used in a MOVEM instruction *)
-
- TYPE
- MReg = (D0, D1, D2, D3, D4, D5, D6, D7,
- A0, A1, A2, A3, A4, A5, A6, A7);
-
- VAR
- i, j : CARDINAL;
- ch : CHAR;
- C : CARDINAL; (* ORD value of ch *)
- T1, T2 : MReg; (* Temporary variables for registers *)
- RegStack : ARRAY [0..15] OF MReg; (* Holds specified registers *)
- SP : CARDINAL; (* Pointer for Register Stack *)
- RegType : (D, A, Nil);
- Range : BOOLEAN;
-
- BEGIN
- SP := 0;
- Range := FALSE;
- RegType := Nil;
- i := 0;
-
- ch := Oper[i];
- WHILE ch # 0C DO
- IF SP > 15 THEN
- Error (Loc, SizeErr);
- RETURN;
- END;
-
- C := ORD (ch);
- IF ch = 'A' THEN
- IF RegType = Nil THEN
- RegType := A;
- ELSE
- Error (Loc, OperErr);
- RETURN;
- END;
- ELSIF ch = 'D' THEN
- IF RegType = Nil THEN
- RegType := D;
- ELSE
- Error (Loc, OperErr);
- RETURN;
- END;
- ELSIF (C >= Zero) AND (C <= Seven) THEN
- IF RegType # Nil THEN
- T2 := VAL (MReg, (ORD (RegType) * 8) + (C - Zero));
- IF Range THEN
- Range := FALSE;
- T1 := RegStack[SP - 1]; (* retreive 1st Reg in range *)
- FOR j := (ORD (T1) + 1) TO ORD (T2) DO
- RegStack[SP] := VAL (MReg, j);
- INC (SP);
- END;
- ELSE
- RegStack[SP] := T2;
- INC (SP);
- END;
- ELSE
- Error (Loc, OperErr);
- RETURN;
- END;
- ELSIF ch = '-' THEN
- IF (Range = FALSE) AND (RegType # Nil) AND (i > 0) THEN
- RegType := Nil;
- Range := TRUE;
- ELSE
- Error (Loc, OperErr);
- RETURN;
- END;
- ELSIF ch = '/' THEN
- IF (Range = FALSE) AND (RegType # Nil) AND (i > 0) THEN
- RegType := Nil;
- ELSE
- Error (Loc, OperErr);
- RETURN;
- END;
- ELSE
- Error (Loc, OperErr);
- RETURN;
- END;
-
- INC (i);
- ch := Oper[i];
- END;
-
- MultExt := {};
- FOR j := 0 TO SP - 1 DO
- C := ORD (RegStack[j]);
- IF PreDec THEN
- C := 15 - C;
- END;
- INCL (MultExt, C);
- END;
- END GetMultReg;
-
- END SyntaxAnalyzer.
-